//name:data_s19.c
//by:yangjinjiang
//date:2017/01/18
//version:v1.0

#include "stm32f4xx_hal.h"
#include "usart.h"
#include "data_hex.h"
#include "delay.h"
#include "main.h"
#include "iwdg.h"
#include "w25qxx.h"
#include "command.h"
#include "short_test.h"

#define	BOOTLOADER_MCU_INI_ADR						0x08000000

const uint32_t	STM32F407_SECTOR[12]= {FLASH_SECTOR_0,FLASH_SECTOR_1,FLASH_SECTOR_2,FLASH_SECTOR_3,FLASH_SECTOR_4,FLASH_SECTOR_5,FLASH_SECTOR_6,FLASH_SECTOR_7,FLASH_SECTOR_8,FLASH_SECTOR_9,FLASH_SECTOR_10,FLASH_SECTOR_11};
uint32_t *pMemFlagAddr = (uint32_t *)(SRAM_BASE+0x2000);
uint16_t	Addr_high16;
uint8_t iapStatus = IAP_STATUS_IDLE;
static DATA_LINE	UserData;
static uint32_t ErrCount;

extern 		uint8_t		u8BreakDownload;
extern 		uint16_t	u16TimDdPerTims;
extern 		uint8_t		u8IdxDownload;
extern		uint8_t 	W25QXX_BUFFER[4096];


void InitDownload(void)
{
    iapStatus = IAP_STATUS_IDLE;
    ErrCount = 0;
    HAL_FLASH_Unlock();
}


void ReportNext(void)
{
    UartPushTxBuffer("next\n");
    UsartSendStart();
    Delay_ms(1);
}

void ReportRepeat(void)
{
    UartPushTxBuffer("repeat\n");
    UsartSendStart();
    Delay_ms(1);
}

uint32_t Common_HexStrToU32(uint8_t * pStr, uint8_t num)
{
    uint8_t i;
    uint32_t value;
    uint8_t tmp;

    value = 0;
    for(i=0; i<num; i++)
    {
        value <<= 4;
        tmp = pStr[i];
        if(tmp >= '0' && tmp <= '9')
        {
            tmp -= '0';
        }
        else if(tmp >= 'A' && tmp <= 'F')
        {
            tmp -= ('A'-10);
        }
        else if(tmp >= 'a' && tmp <= 'f')
        {
            tmp -= ('a'-10);
        }
        value |= tmp;
    }
    return value;
}


void Common_EarseFlashPage(uint32_t Sector, uint8_t VoltageRange)
{
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR);
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGAERR);
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGPERR);
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR);
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR);

    FLASH_WaitForLastOperation(50000);
    FLASH_Erase_Sector(Sector,VoltageRange);
    FLASH_WaitForLastOperation(50000);
}

void Common_ProgramFlash(unsigned int FlashAddr,unsigned char* pData,unsigned int bytes)
{
    unsigned int WriteCount;
    unsigned int i;
    unsigned int *pBuffer;

    pBuffer = (unsigned int *)pData;
    WriteCount = bytes/4;
    if(bytes % 4)
        WriteCount++;

    for(i=0; i<WriteCount; i++)
    {
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,FlashAddr,pBuffer[i]);
        FlashAddr += 4;
    }
}


void WrtieDataToFlash(uint32_t adr, uint8_t *dat, uint32_t length)
{
    uint32_t	tmp1,tmp2;
    if(adr == 0x08000000)
    {
        Common_EarseFlashPage(STM32F407_SECTOR[0],FLASH_VOLTAGE_RANGE_3);	//16k
    }
    else if(adr == 0x08004000)
    {
        Common_EarseFlashPage(STM32F407_SECTOR[1],FLASH_VOLTAGE_RANGE_3);	//16k
    }
    else if(adr == 0x08008000)
    {
        Common_EarseFlashPage(STM32F407_SECTOR[2],FLASH_VOLTAGE_RANGE_3);	//16k
    }
    else if(adr == 0x0800C000)
    {
        Common_EarseFlashPage(STM32F407_SECTOR[3],FLASH_VOLTAGE_RANGE_3);	//16k
    }
    else if(adr == 0x08010000)
    {
        Common_EarseFlashPage(STM32F407_SECTOR[4],FLASH_VOLTAGE_RANGE_3);	//64k
    }
    else if(adr>=0x08020000)																 					 	//128k
    {
        tmp1=adr - 0x08020000;
        if(tmp1==0)
        {
            Common_EarseFlashPage(STM32F407_SECTOR[5],FLASH_VOLTAGE_RANGE_3);
        }
        else
        {
            tmp2=tmp1%131072;																							//128k==131072
            if(tmp2==0)
            {
                tmp1/=131072;
                Common_EarseFlashPage(STM32F407_SECTOR[5+tmp1],FLASH_VOLTAGE_RANGE_3);
            }
        }
    }

    Common_ProgramFlash(adr,dat,length);
}

void DownloadDataToMCU(uint32_t ext_flash_ini_adr, uint32_t length, uint32_t MCU_ini_adr)
{
    uint32_t 	read_num = length, remain = 4096;
    uint32_t	read_ini_adr = ext_flash_ini_adr;

    if(read_ini_adr > FLASH_END_ADR)
    {
        return;
    }

    if(read_num <= remain)
    {
        remain = read_num;
    }

    __HAL_RCC_TIM3_CLK_DISABLE();
    __HAL_RCC_USART1_CLK_DISABLE();

    HAL_NVIC_DisableIRQ(USART1_IRQn);
    HAL_NVIC_DisableIRQ(TIM3_IRQn);

    while(1)
    {
        if((read_ini_adr + remain) > FLASH_END_ADR)
        {
            remain = FLASH_END_ADR - read_ini_adr + 1;
            read_num = remain;
        }

        W25QXX_Read(W25QXX_BUFFER,read_ini_adr,remain);
        WrtieDataToFlash(read_ini_adr -FLASH_BOOT_INI_ADR + BOOTLOADER_MCU_INI_ADR,W25QXX_BUFFER,remain);

        if(read_num == remain)
        {
            break;
        }
        else
        {
            read_ini_adr += remain;
            read_num -= remain;

            if(read_num > 4096)
            {
                remain = 4096;
            }
            else
            {
                remain = read_num;
            }
        }
    }

    __HAL_RCC_TIM3_CLK_ENABLE();
    __HAL_RCC_USART1_CLK_ENABLE();

    HAL_NVIC_EnableIRQ(USART1_IRQn);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);
}




void GetDataHex(unsigned char* pBuff,DATA_LINE *pData)
{
    uint16_t 	i;
    uint8_t 	tmp;
    static 	uint32_t	adr;
    static  uint8_t		count;

    switch(iapStatus)
    {
    case IAP_STATUS_START:
        pData->head = pBuff[0];
        pBuff ++;
        if(pData->head == ':')
        {
            pData->checksum = 0;
            pData->count = Common_HexStrToU32(pBuff,2);
            pBuff += 2;
            pData->checksum  += pData->count;
            pData->address = 0;
            for(i=0; i<2; i++)
            {
                pData->address <<= 8;
                tmp = Common_HexStrToU32(pBuff,2);
                pData->address |= tmp;
                pData->checksum  += tmp;
                pBuff += 2;
            }

//				sprintf(StrTmp,"address00:%x\n",pData->address);
//						UartPushTxBuffer(StrTmp);
//						UsartSendStart();
//
            pData->type = Common_HexStrToU32(pBuff,2);
            pBuff += 2;
            pData->checksum  += pData->type;
            for(i=0; i<pData->count; i++)
            {
                pData->data[i] = Common_HexStrToU32(pBuff,2);
                pBuff += 2;
                pData->checksum += pData->data[i];
            }
            pData->checksum &= 0xff;													//the checking methods of hex is different from s19 file
            pData->checksum = 0x100-pData->checksum;
            pData->checksum &= 0xff;

            tmp = Common_HexStrToU32(pBuff,2);
//						sprintf(StrTmp,"num=%d  tmp=%x  checksum=%x\n",num++,tmp,pData->checksum);
//						UartPushTxBuffer(StrTmp);
//						UsartSendStart();
            if(pData->checksum != tmp)
            {
                ErrCount++;
                ReportRepeat();
            }
            else
            {
                u8BreakDownload = 0;
                u16TimDdPerTims = 0;
                if(pData->type == 0x01)
                {
                    iapStatus = IAP_STATUS_END;
                }
                else if(pData->type == 0x00)
                {
//						if(pData->address >= 0x9400)				//address more than 0x9400 we don't need to update.
//						{
//							ErrCount++;
//						}
//						else
//						{
//							SaveDataToSpiFlash(pData);
//						}
//						for(i = 0; i<32 ;i++)
//						{
//							sprintf(StrTmp,"i%d:%x\n",i,pData->data[i]);
//							UartPushTxBuffer(StrTmp);
//							UsartSendStart();
//						}

//						sprintf(StrTmp,"num=%d\n",num++);
//						UartPushTxBuffer(StrTmp);
//						UsartSendStart();

                    adr = ((uint32_t)Addr_high16<<16) | (pData->address & 0x0000ffff);
                    count = pData->count;
                    W25QXX_Download(pData->data,adr - BOOTLOADER_MCU_INI_ADR +FLASH_BOOT_INI_ADR,count);

//						sprintf(StrTmp,"address02:%x\n",pData->address);
//						UartPushTxBuffer(StrTmp);
//						UsartSendStart();

//						W25QXX_Read(W25QXX_BUFFER,pData->address - BOOTLOADER_MCU_INI_ADR +FLASH_BOOT_INI_ADR ,32);
//						for(i = 0; i<32 ;i++)
//						{
//							sprintf(StrTmp,"i%d:%x\n",i,W25QXX_BUFFER[i]);
//							UartPushTxBuffer(StrTmp);
//							UsartSendStart();
//						}
                }
                else if(pData->type == 0x04)
                {
                    Addr_high16 = ((uint16_t)pData->data[0]<<8) | pData->data[1];
//						sprintf(StrTmp,"addr_high16:%x\n",addr_high16);
//						UartPushTxBuffer(StrTmp);
//						UsartSendStart();
                }
                u8BreakDownload = 1;
                u16TimDdPerTims = 0;
                ReportNext();
            }
        }
        break;

    case IAP_STATUS_END:
        if(CmpStr(pBuff,"update end",10))
        {
            u16TimDdPerTims=0;
            u8BreakDownload=0;

            DownloadDataToMCU(FLASH_BOOT_INI_ADR, adr - BOOTLOADER_MCU_INI_ADR + count, BOOTLOADER_MCU_INI_ADR);

//				sprintf(StrTmp,"bytes:%x\n",adr - BOOTLOADER_MCU_INI_ADR + count);
//				UartPushTxBuffer(StrTmp);
//				UsartSendStart();

            Delay_ms(20);
            ReportNext();
            Delay_ms(20);

            iapStatus = IAP_STATUS_FINISH;
            __set_FAULTMASK(1);
            *pMemFlagAddr = MEM_DOWNLOAD_FLAG+1;
            NVIC_SystemReset();
        }
        break;
    }
}

void DataProcess(void)
{
    GetDataHex(UartRxBuffer,&UserData);
}




